﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ReadyApps.Data;
using System.Text.RegularExpressions;
using System.Web.Routing;

namespace ReadyApps.Models.Wiki
{
    class WikiPage
    {
        #region Variables

        private int pageID;
        private int folderID;
        private string pageTitle;
        private List<IWikiPageComponent> pageComponents;
        private IWikiUrlManager urlManager;

        private static readonly Regex splittingPattern = new Regex(@"(\{\[link:\d+\]\})", RegexOptions.Compiled);

        #endregion

        #region Properties

        /// <summary>
        /// Gets the status of component generation within the <see cref="WikiPage"/>.
        /// </summary>
        private bool ComponentsGenerated
        {
            get { return pageComponents != null; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Creates a new instance of the WikiPage class to manage the creation and update
        /// of the wiki control's components.
        /// </summary>
        /// <param name="urlManager">The <see cref="IWikiUrlManager"/> for generating URLs
        /// to other pages within the same wiki hierarchy</param>
        public WikiPage(IWikiUrlManager urlManager)
        {
            if (urlManager == null)
            {
                throw new ArgumentNullException("urlManager");
            }
            this.urlManager = urlManager;
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Generates the internal wiki components based on the supplied <see cref="WikiPageData"/>
        /// object.
        /// </summary>
        /// <exception cref="ArgumentNullException">The pageData parameter is null</exception>
        /// <param name="pageData">The <see cref="WikiPageData"/> to generate wiki components
        /// from</param>
        public void GenerateWikiComponentsFromPageData(WikiPageData pageData)
        {
            if (pageData == null)
            {
                throw new ArgumentNullException("pageData");
            }
            pageComponents = new List<IWikiPageComponent>();
            pageID = pageData.PageID;
            folderID = pageData.FolderID;
            pageTitle = pageData.PageTitle;
            string[] pageContentPieces = splittingPattern.Split(pageData.PageContent);
            pageComponents = new List<IWikiPageComponent>();
            Match match;
            foreach (var contentPiece in pageContentPieces)
            {
                if (!string.IsNullOrEmpty(contentPiece))
                {
                    match = WikiPageLink.MatchComparison.Match(contentPiece);
                    if (match.Success)
                    {
                        int pageLinkKey = Convert.ToInt32(match.Groups[1].Value);
                        WikiPageLinkData pageLinkData = pageData.PageLinks.Where(pl => pl.PageLinkKey == pageLinkKey).First();
                        string linkUrl = pageLinkData.IsManagedLink ? urlManager.GetVirtualUrl(pageLinkData.LinkUrl) : pageLinkData.LinkUrl;
                        pageComponents.Add(new WikiPageLink(pageLinkKey, pageLinkData.DisplayText, linkUrl, pageLinkData.Target));
                    }
                    else
                    {
                        pageComponents.Add(new WikiPageText(contentPiece));
                    }
                }
            }
        }

        /// <summary>
        /// Generates the wiki components for a non-existent page which in general tells
        /// the user that the requested URL does not appear to be valid.
        /// </summary>
        public void GenerateWikiComponentsForNonExistentPage()
        {
            pageComponents = new List<IWikiPageComponent>();
            pageComponents.Add(new WikiPageText(@"
<h1 style=""color: Red;"">Page Not Found</h1>
<p>The requested page was not found. Please check the URL for correctness or report
a bad link to the website administrator.</p>
"));
        }

        /// <summary>
        /// Gets an IEnumerable collection of the wiki components for ASP.Net control creation.
        /// </summary>
        /// <remarks>
        /// This method must be preceded by a call to GenerateWikiComponentsFromPageData or
        /// GenerateWikiComponentsForNonExistentPage. This ensures that the internal state of the
        /// wiki components is initialized.
        /// </remarks>
        /// <exception cref="InvalidOperationException">The method was called before a GenerateWikiComponents
        /// method</exception>
        /// <returns>An <see cref="IEnumerable{IWikiPageComponent}"/> of the page components</returns>
        public IEnumerable<IWikiPageComponent> GetWikiComponents()
        {
            if (!ComponentsGenerated)
            {
                throw new InvalidOperationException("Wiki components have not been generated yet. Calls to GetWikiComponents " +
                    "must be preceded by a call to GenerateWikiComponentsFromPageData or GenerateWikiComponentsForNonExistentPage.");
            }
            return pageComponents.AsReadOnly();
        }

        #endregion
    }
}
